#include "crossbit/Profiler.h"
#include "crossbit/VInst.h"
#include "crossbit/common.h"
#include "vector"
using namespace crossbit;
Profiler::Profiler(){
}
Profiler::~Profiler(){
}
VBlock* Profiler::buildSuperVBlock( TCache* cache , XTMemAddr spc ){
		VBlock* head = new VBlock( spc );
		XTMemAddr branch, follow;
		std::vector<XTMemAddr> chain;

		for( int i = 0 ; i < GLOBAL::MAX_BLOCK_CHAIN_NUM ; i++ ){
				VBlock *vblock =  cache -> lookupVBlock( spc );
				if( cache -> lookupTBlock( spc ) -> isSupperBlock() ) break;
				if( vblock == NULL ) break;
				
				int j = 0;
				for( ; j < chain.size() ; j++ ) if( chain[j] == spc ) break;
				if( j < chain.size() ) break;

				VBlock::vb_reverse_iterator it = vblock -> rbegin(); 
				if( (*it) -> getOpcode() != OP_BRANCH || (*it) -> getOperand(4).reg != 0 )
						break;

				branch = (*it) -> getOperand(5).imm;
				follow = vblock -> nextSPC();
				
				TBlock *branch_tblock = cache -> lookupTBlock( branch );
				TBlock *follow_tblock = cache -> lookupTBlock( follow );

				if( branch_tblock == NULL && follow_tblock == NULL )
						break;

				chain.push_back(spc);

				if( branch_tblock == NULL )  spc = follow;
				else if( follow_tblock == NULL ) spc = branch;
				else if( branch_tblock -> getRunCount() > follow_tblock -> getRunCount() )
						spc = branch;
				else
						spc = follow;
		}

		if( chain.size() == 0 ){
			     	
				return NULL;
		} 

		//for( int i = 0 ; i < chain.size() ; i++ ) printf("%x\t" , chain[i]);
	//	printf("\n");
		for( int i = 0 ; i < chain.size(); i++ ){
				VBlock *vblock = cache -> lookupVBlock( chain[i] );
				VBlock::vb_iterator left = vblock -> begin();

				while( left != vblock -> end() ){
						head -> push_back( *left );
						++left;
				}
			    //printf("add = %x\n" , chain[i] );	
				//vblock -> print( std::cout );
				if( i == chain.size() - 1 ){
						head -> setVbNextSpc( vblock -> nextSPC() );
						break;
				} 

				if( vblock -> nextSPC() != chain[i+1] ){
						
						VBlock::vb_reverse_iterator it = head -> rbegin();
						Operand ccp = (*it) -> getOperand( 1 );

						if( ccp.cc == EQ ) ccp.cc = NE;
						else if( ccp.cc == NE ) ccp.cc = EQ;
						else if( ccp.cc == GT ) ccp.cc = LE; 
						else if( ccp.cc == LE ) ccp.cc = GT; 
						else if( ccp.cc == GE ) ccp.cc = LT; 
						else if( ccp.cc == LT ) ccp.cc = GE; 
						else if( ccp.cc == AB ) ccp.cc = BE; 
						else if( ccp.cc == BE ) ccp.cc = AB; 

					//	(*it) -> setOperand( 1 , ccp );
						Operand opr_2 = (*it) -> getOperand(2);
						Operand opr_3 = (*it) -> getOperand(3);
						Operand opr_4 = (*it) -> getOperand(4);
						
					    VInst* vinst = VInst5::createBRANCH( ccp.cc , opr_2.reg , opr_3.reg , opr_4.reg, vblock -> nextSPC()); 
						head -> erase( --(head -> end()) );
						head -> push_back( vinst ); 
			/*			Operand dst = (*it) -> getOperand(5);
						XTMemAddr former_addr = dst.imm;
						dst.imm = vblock -> nextSPC();
						// correct ? as the may affect the former vblock

						(*it) -> setOperand( 5 , dst );
						vblock -> setVbNextSpc( former_addr );  
			*/
				}
		}
		return head;
}	


